package com.chenfan.mcn.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.utils.DateUtils;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SDepartment;
import com.chenfan.mcn.clients.privilege.SUserVo;
import com.chenfan.mcn.dao.MonthlyTargetMapper;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.model.McnPage;
import com.chenfan.mcn.model.MonthlyTarget;
import com.chenfan.mcn.model.dto.MonthlyTargetDTO;
import com.chenfan.mcn.model.dto.MonthlyTargetSearchDTO;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.service.MonthlyTargetService;
import com.chenfan.mcn.utils.BusinessAssert;
import com.chenfan.mcn.utils.DateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门月度目标 服务实现类
 * </p>
 *
 * @author lizhejin
 * @since 2021-10-19
 */
@Service
public class MonthlyTargetServiceImpl implements MonthlyTargetService {

    @Autowired
    private MonthlyTargetMapper monthlyTargetMapper;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Override
    public List<MonthlyTargetDetailVO> amountDetails(String monthlyCode) {
        if (StrUtil.isBlank(monthlyCode)) {
            throw new BusinessException(McnErrorCode.PLEASE_CHOOSE_MONTHLY_CODE);
        }
        List<SDepartment> businessDepartments = privilegeClient.getBusinessDepartment().getObj();
        List<Long> departmentIds = businessDepartments.stream().map(SDepartment::getDepartmentId).collect(Collectors.toList());
        List<MonthlyTarget> monthlyTargets = monthlyTargetMapper.selectList(Wrappers.lambdaQuery(MonthlyTarget.class)
                .eq(MonthlyTarget::getMonthlyCode, monthlyCode)
                .in(MonthlyTarget::getTargetDepartmentId, departmentIds)
                .eq(MonthlyTarget::getIsDelete, Boolean.FALSE));
        Map<Long, BigDecimal> targetAmountMap = new HashMap<>(16);
        if (CollectionUtil.isNotEmpty(monthlyTargets)) {
            targetAmountMap = monthlyTargets.stream().collect(Collectors.toMap(MonthlyTarget::getTargetDepartmentId, MonthlyTarget::getTargetAmount));
        }
        List<MonthlyTargetDetailVO> departmentTargetDetailList = new ArrayList<>();
        for (SDepartment businessDepartment : businessDepartments) {
            Long departmentId = businessDepartment.getDepartmentId();
            MonthlyTargetDetailVO monthlyTargetDetail = new MonthlyTargetDetailVO();
            monthlyTargetDetail.setDepartmentId(departmentId);
            monthlyTargetDetail.setDepartmentName(businessDepartment.getDepartmentName());
            if (targetAmountMap.containsKey(businessDepartment.getDepartmentId())) {
                monthlyTargetDetail.setTargetAmount(targetAmountMap.get(departmentId));
            }
            departmentTargetDetailList.add(monthlyTargetDetail);
        }
        return departmentTargetDetailList;
    }

    @Override
    public MonthlyTargetDTO targetDetail(Long id) {
        MonthlyTarget monthlyTarget = monthlyTargetMapper.selectById(id);
        if (monthlyTarget == null) {
            throw new BusinessException(McnErrorCode.MONTHLY_TARGET_NOT_EXIST);
        }
        MonthlyTargetDTO monthlyTargetDTO = new MonthlyTargetDTO();
        BeanUtils.copyProperties(monthlyTarget, monthlyTargetDTO);
        Map<Long, SDepartment> departmentMap = privilegeClient.getDepartmentByIds(Collections.singletonList(monthlyTargetDTO.getTargetDepartmentId())).getObj();
        if (departmentMap.containsKey(monthlyTargetDTO.getTargetDepartmentId())) {
            monthlyTargetDTO.setTargetDepartmentName(departmentMap.get(monthlyTargetDTO.getTargetDepartmentId()).getDepartmentName());
        }
        return monthlyTargetDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteTarget(Long id) {
        MonthlyTarget entity = monthlyTargetMapper.selectById(id);
        BusinessAssert.notNull(entity, McnErrorCode.MONTHLY_TARGET_NOT_EXIST);
        MonthlyTarget monthlyTarget = new MonthlyTarget();
        monthlyTarget.setId(entity.getId());
        monthlyTarget.setIsDelete(1);
        return monthlyTargetMapper.updateById(monthlyTarget);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateTarget(MonthlyTargetDTO monthlyTargetDTO) {
        MonthlyTarget entity = monthlyTargetMapper.selectById(monthlyTargetDTO.getId());
        BusinessAssert.notNull(entity, McnErrorCode.MONTHLY_TARGET_NOT_EXIST);
        MonthlyTarget updateMonthlyTarget = new MonthlyTarget();
        updateMonthlyTarget.setId(entity.getId());
        updateMonthlyTarget.setTargetAmount(monthlyTargetDTO.getTargetAmount());
        return monthlyTargetMapper.updateById(updateMonthlyTarget);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addTarget(List<MonthlyTargetDTO> monthlyTargetList) {
        verifyInsertParam(monthlyTargetList);
        verifyTargetCount(monthlyTargetList);
        List<MonthlyTarget> monthlyTargets = new ArrayList<>();
        for (MonthlyTargetDTO monthlyTargetDTO : monthlyTargetList) {
            MonthlyTarget monthlyTarget = new MonthlyTarget();
            monthlyTarget.setMonthlyCode(monthlyTargetDTO.getMonthlyCode());
            monthlyTarget.setTargetAmount(monthlyTargetDTO.getTargetAmount());
            monthlyTarget.setTargetDepartmentId(monthlyTargetDTO.getTargetDepartmentId());
            monthlyTargets.add(monthlyTarget);
        }
        return monthlyTargetMapper.insertBatch(monthlyTargets);
    }

    @Override
    public MonthlyTargetListVO targetList(MonthlyTargetSearchDTO dto) {
        if (StrUtil.isBlank(dto.getMonthlyCode())) {
            throw new BusinessException(McnErrorCode.PLEASE_CHOOSE_MONTHLY_CODE);
        }
        String startTime = DateUtil.startTime(dto.getMonthlyCode());
        String endTime = DateUtil.endTime(dto.getMonthlyCode());
        // 获取所有商务部门
        List<SDepartment> sDepartments = privilegeClient.getBusinessDepartment().getObj();
        Map<Long, SDepartment> departmentNameMap = sDepartments.stream().collect(Collectors.toMap(SDepartment::getDepartmentId, a -> a));
        // 获取部门负责人信息
        List<Long> departmentHeadIds = sDepartments.stream().map(SDepartment::getDepartmentHeadId).collect(Collectors.toList());
        List<SUserVo> departmentHeaders = privilegeClient.getDepartmentByUserIds(departmentHeadIds).getObj();
        Map<Long, String> userNameMap = departmentHeaders.stream().collect(Collectors.toMap(SUserVo::getUserId, SUserVo::getUsername));

        List<Long> departmentIds = sDepartments.stream().map(SDepartment::getDepartmentId).collect(Collectors.toList());
        dto.setAlias("c.");
        dto.setDepartmentIds(departmentIds);
        List<MonthlyTargetList> monthlyTargetList = monthlyTargetMapper.targetList(dto, startTime, endTime);
        if (CollectionUtil.isNotEmpty(monthlyTargetList)) {
            for (MonthlyTargetList targetList : monthlyTargetList) {
                BigDecimal sum = targetList.getTotalSales().add(targetList.getTotalSharePerformance());
                BigDecimal divide;
                if (targetList.getTargetAmount().compareTo(BigDecimal.ZERO) > 0) {
                    divide = sum.divide(targetList.getTargetAmount(), 4, BigDecimal.ROUND_HALF_UP);
                } else {
                    divide = BigDecimal.ONE;
                }
                targetList.setTargetReachRate(divide);
                Long targetDepartmentId = targetList.getTargetDepartmentId();
                if (departmentNameMap.containsKey(targetDepartmentId)) {
                    targetList.setTargetDepartmentName(departmentNameMap.get(targetDepartmentId).getDepartmentName());
                    targetList.setDepartmentHeadId(departmentNameMap.get(targetDepartmentId).getDepartmentHeadId());
                }
                if (userNameMap.containsKey(targetList.getDepartmentHeadId())) {
                    targetList.setDepartmentHeadName(userNameMap.get(targetList.getDepartmentHeadId()));
                }
            }
        }
        MonthlyTargetListVO monthlyTargetListVO = new MonthlyTargetListVO();
        monthlyTargetListVO.setMonthlyTargetList(monthlyTargetList);
        BigDecimal totalMonthlySales = monthlyTargetMapper.getTotalMonthlySales(startTime, endTime);
        monthlyTargetListVO.setTotalMonthlySales(totalMonthlySales);
        return monthlyTargetListVO;
    }

    @Override
    public Page<MonthlyTargetPageVO> targetPage(McnPage<MonthlyTargetPageVO> mcnPage, MonthlyTargetSearchDTO dto) {
        if (dto.getTargetDepartmentId() == null) {
            throw new BusinessException(McnErrorCode.PARAM_ERROR);
        }
        dto.setAlias("c.");
        Page<MonthlyTargetPageVO> monthlyTargetPageVO = monthlyTargetMapper.targetPage(mcnPage, dto);
        if (CollectionUtil.isNotEmpty(monthlyTargetPageVO.getRecords())) {
            for (MonthlyTargetPageVO pageVO : monthlyTargetPageVO.getRecords()) {
                BigDecimal sum = pageVO.getTotalSales().add(pageVO.getTotalSharePerformance());
                BigDecimal divide;
                if (pageVO.getTargetAmount().compareTo(BigDecimal.ZERO) > 0) {
                    divide = sum.divide(pageVO.getTargetAmount(), 4, BigDecimal.ROUND_HALF_UP);
                } else {
                    divide = BigDecimal.ONE;
                }
                pageVO.setTargetReachRate(divide);
            }
        }
        return monthlyTargetPageVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateMonthlySales(Date date) {
        MonthlyTargetSearchDTO searchDTO = new MonthlyTargetSearchDTO();
        searchDTO.setEnabled(false);
        searchDTO.setMonthlyCode(DateUtils.formatDate(date, "yyyyMM"));
        MonthlyTargetListVO vo = this.targetList(searchDTO);
        if(CollectionUtils.isNotEmpty(vo.getMonthlyTargetList())) {
            vo.getMonthlyTargetList().forEach(data -> {
                MonthlyTarget monthlyTarget = new MonthlyTarget();
                monthlyTarget.setId(data.getId());
                monthlyTarget.setTotalSales(data.getTotalSales());
                monthlyTarget.setTotalSharePerformance(data.getTotalSharePerformance());
                monthlyTarget.setTargetReachRate(data.getTargetReachRate());
                monthlyTarget.setUpdateDate(new Date());
                monthlyTargetMapper.updateById(monthlyTarget);
            });
        }
    }


    private void verifyInsertParam(List<MonthlyTargetDTO> monthlyTargetList) {
        if (CollectionUtil.isEmpty(monthlyTargetList)) {
            throw new BusinessException(McnErrorCode.PARAM_ERROR);
        }
        monthlyTargetList.forEach(d -> {
            boolean paramError = d.getTargetDepartmentId() == null
                    || d.getTargetAmount() == null || StrUtil.isBlank(d.getMonthlyCode());
            if (paramError) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
        });
    }


    private void verifyTargetCount(List<MonthlyTargetDTO> monthlyTargetList) {
        for (MonthlyTargetDTO monthlyTargetDTO : monthlyTargetList) {
            LambdaQueryWrapper<MonthlyTarget> queryWrapper = Wrappers.lambdaQuery(MonthlyTarget.class)
                    .eq(MonthlyTarget::getMonthlyCode, monthlyTargetDTO.getMonthlyCode())
                    .eq(MonthlyTarget::getTargetDepartmentId, monthlyTargetDTO.getTargetDepartmentId())
                    .eq(MonthlyTarget::getIsDelete, Boolean.FALSE);
            Integer existCount = monthlyTargetMapper.selectCount(queryWrapper);
            if (existCount > 0) {
                throw new BusinessException(McnErrorCode.MONTHLY_TARGET_EXIST);
            }
        }
    }

}
